using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace IOUtils
{
    /// <summary>
    /// BinaryInputStream which allows swaping of endianness while reading the data.
    /// Class uses bit shiffting to convert the data between endians.
    /// 
    /// Currently (U)Int63 not implemented.
    /// Currently No signs are being interpreted during swapping where required.
    /// </summary>
    class BinaryReaderES : BinaryReader
    {   
        /// <summary>
        /// Boolean to indicate whether we need to swap endianness. 
        /// This is relative to the data source as aposed to the OS.
        /// </summary>
        public Boolean swap = false;
       

        /// <summary>
        /// Default Constructor.
        /// </summary>
        /// <param name="stream">Stream to be read.</param>
        public BinaryReaderES(Stream stream) : base(stream) 
        {
        }     


        /// <summary>
        /// Reads a Double from the Stream, 
        /// swapping endianness when required.
        /// </summary>
        /// <returns>A Double</returns>
        public override Double ReadDouble()
        { 
            if (swap == false)
                return base.ReadDouble();

            byte one   = base.ReadByte();
            byte two   = base.ReadByte();
            byte three = base.ReadByte();
            byte four  = base.ReadByte();
            byte five  = base.ReadByte();
            byte six   = base.ReadByte();
            byte seven = base.ReadByte();
            byte eight = base.ReadByte();

            return Convert.ToDouble((one << 56) | (two << 48) | (three << 40) | (four << 32) | (five << 24) | (six << 16) | (seven << 8) | eight);            
        }


        /// <summary>
        /// Reads a Int16 from the Stream, 
        /// swapping endianness when required.
        /// </summary>
        /// <returns>A Int16</returns>
        public override Int16 ReadInt16()
        {
            if (swap == false)
                return base.ReadInt16();

            byte one = base.ReadByte();
            byte two = base.ReadByte();

            return Convert.ToInt16((one << 8) | two);          
        }


        /// <summary>
        /// Reads a Int32 from the Stream, 
        /// swapping endianness when required.
        /// </summary>
        /// <returns>A Int32</returns>
        public override Int32 ReadInt32()
        {
           if (swap == false)
            return base.ReadInt32();

            byte one   = base.ReadByte();
            byte two   = base.ReadByte();
            byte three = base.ReadByte();
            byte four  = base.ReadByte();

            return Convert.ToInt32((one << 24) | (two << 16) | (three << 8) | four);                   
        }


        /// <summary>
        /// Reads a Int64 from the Stream, 
        /// swapping endianness when required.
        /// </summary>
        /// <returns>A Int64</returns>
        public override Int64 ReadInt64()
        {
            // FIX ME!!
            return base.ReadInt64();            
        }


        /// <summary>
        /// Reads a UInt16 from the Stream, 
        /// swapping endianness when required.
        /// </summary>
        /// <returns>A UInt16</returns>
        public override UInt16 ReadUInt16()
        {
            if (swap == false)
                base.ReadUInt16();

            byte one  = base.ReadByte();
            byte two  = base.ReadByte();            

            return Convert.ToUInt16((one << 8) | two);                
        }


        /// <summary>
        /// Reads a UInt32 from the Stream, 
        /// swapping endianness when required.
        /// </summary>
        /// <returns>A UInt32</returns>
        public override UInt32 ReadUInt32()
        {
            if (swap == false)
                 return base.ReadUInt32();

             byte one = base.ReadByte();
             byte two = base.ReadByte();
             byte three = base.ReadByte();
             byte four = base.ReadByte();

             return Convert.ToUInt32((one << 24) | (two << 16) | (three << 8) | four);                      
        }


        /// <summary>
        /// Reads a UInt64 from the Stream, 
        /// swapping endianness when required.
        /// </summary>
        /// <returns>A UInt64</returns>
        public override UInt64 ReadUInt64()
        {
            // FIX ME!!
            return base.ReadUInt64();           
        }


        /// <summary>
        /// Reads a DSingle from the Stream, 
        /// swapping endianness when required.
        /// </summary>
        /// <returns>A Single</returns>
        public override Single ReadSingle()
        {
            if (swap == false)
                return base.ReadSingle();

            byte one   = base.ReadByte();
            byte two   = base.ReadByte();
            byte three = base.ReadByte();
            byte four  = base.ReadByte();

            return Convert.ToSingle((one << 24) | (two << 16) | (three << 8) | four);          
        }
    }
}